Матч 325, Починка забора (FenceRepairing)

Дивизион 1, Уровень 1

 

Вам необходимо починить старый забор. Забор состоит из набора досок, некоторые из которых выломаны. Доски пронумерованы слева направо в возрастающем порядке. Починка всех досок от i - ой до j - ой (i < j) стоит . Целые доски обозначаются символом ‘. (точка), сломанные – ‘X’. Для уменьшения общей стоимости ремонта иногда выгодно ремонтировать даже целые доски. Необходимо найти минимальную стоимость ремонта всего забора.

 

Класс: FenceRepairing

Метод: double calculateCost(vector<string> boards)

Ограничения: boards содержит от 1 до 50 элементов, boards[i]  содержит от 1 до 50 символов ‘.’ И ‘X’.

 

Вход. Массив строк boards. Объединив их, получим состояние забора, который подлежит ремонту.

 

Выход. Минимальная стоимость ремонта всего забора.

 

Пример входа

boards

{"X.X...X.X"}

{"X.X.....X"}

{".X.......X", "..........", "...X......", "...X..X...", "..........",

"..........", "..X....XX.", ".........X", "XXX", ".XXX.....X"}

 

Пример выхода

3.0

2.732050807568877

9.591663046625438

 

 

РЕШЕНИЕ

динамическое программирование

 

Исходя из ограничений на массив boards и на длины его элементов, заключаем, что длина наибольшего возможного входного забора не более 50*50 = 2500. Объединим строки массива boards в b. Заведем массив c длины 2501, в котором c[i] будет хранить минимальную стоимость, за которую можно починить забор от нулевой позиции до (i – 1) - ой, причем c[0] положим равным 0. Тогда дешевле всего починить первые i секции (от 0 - ой до (i – 1) - ой) забора следующим образом:

1. Если i - ая секция цела (b[i – 1] = ‘.’), то достаточно починить только первые i – 1 секций: c[i] = c[i – 1];

2. Если i - ая секция сломана (b[i – 1] = ‘X’), то чиним забор от 0 - ой до j - ой секции (0 £ j < i), потратив c[j] денег, а затем чиним доски от (j + 1) - ой до i - ой секции за  денег. При этом среди всех возможных j следует выбрать такое, для которого сумма c[j] +  наименьшая.

Положив c[0] = 0, последовательно вычисляем c[1], c[2] , …, c[n], где n – длина забора. Ответом задачи будет значение c[n].

 

ПРОГРАММА

 

#include <cstdio>

#include <vector>

#include <string>

#include <cmath>

#include <numeric>

#define min(i,j) (i < j) ? i : j

using namespace std;

 

class FenceRepairing

{

public:

  double calculateCost(vector<string> boards)

  {

    string b = accumulate(boards.begin(),boards.end(),string());

    int i, j;

    double c[2501];

    for(c[0] = 0, i = 1; i <= b.size(); i++)

    {

      c[i] = 2000000000;

      if (b[i-1] == '.') c[i] = c[i-1]; else

      for(j = 0; j < i; j++)

        c[i] = min(c[i],c[j] + sqrt(1.0 * i - j));

    }

    return c[b.size()];

  }

};